package cube

import (
	"fmt"
	"strconv"
	"strings"
	"time"

	"shqsoft.cn/pasnj/base"
	"shqsoft.cn/pasnj/bi/datapackage"

	"github.com/go-redis/redis"
	uuid "github.com/satori/go.uuid"
)

//CacheDuration 缓存时间
const CacheDuration = time.Hour * 8

var cacheRedisCli = base.RedisClients[0]

//Level 层次级别
type Level struct {
	redisCli  *redis.Client
	setting   *datapackage.Level
	lKey      string
	hKey      string
	sKey      string
	flterKeys []string
	index     int
	hie       *Hierarchy
	filters   []filter
	sorts     []sort
}

type filter struct {
	Type     string
	Name     string
	Operator string
	Value    string
	Context  string
}
type sort struct {
	Type    string
	Column  string
	Order   string
	Context string
}

//GetRange 获取两值之间的所有keys
func (l *Level) GetRange(startVal, endVal string) ([]string, error) {
	start := int64(0)
	eachCount := int64(1000)
	end := int64(999)
	rKeys := make([]string, 0)
	isBegin := false
	isEnd := false
	for {
		keys, err := l.redisCli.LRange(l.lKey, start, end).Result()
		if err != nil {
			return nil, fmt.Errorf("获取维度层次段值时，调用redis命令LRange出错:%s", err)
		}
		if len(keys) == 0 {
			break
		}
		for _, key := range keys {
			if key == startVal {
				isBegin = true
			}
			if isBegin && !isEnd {
				rKeys = append(rKeys, key)
			}
			if key == endVal {
				isEnd = true
			}
		}
		start += eachCount
		end += eachCount
	}
	return rKeys, nil
}

//SetFilterByLabel 设置通过维度层次的名称过滤
func (l *Level) SetFilterByLabel(operator, val string) *Level {
	f := filter{
		Type:     "label",
		Operator: operator,
		Value:    val,
	}
	l.filters = append(l.filters, f)
	return l
}

//SetFilterByProperty 设置通过维度层次属性过滤
func (l *Level) SetFilterByProperty(name, operator, val string) *Level {
	f := filter{
		Name:     name,
		Type:     "property",
		Operator: operator,
		Value:    val,
	}
	l.filters = append(l.filters, f)
	return l
}

//SetFilterByMeasure 设置通过维度层次度量值过滤
func (l *Level) SetFilterByMeasure(name, operator, val, context string) *Level {
	f := filter{
		Name:     name,
		Type:     "measure",
		Operator: operator,
		Value:    val,
		Context:  context,
	}
	l.filters = append(l.filters, f)
	return l
}
func (l *Level) filterByName(name, operator, val string) error {
	newKeys := make([]string, 0)
	for _, key := range l.flterKeys {
		lName, err := l.redisCli.HGet(l.hKey+key, name).Result()
		if err != nil {
			return fmt.Errorf("过滤维度层次时，调用redis命令HGet出错:%s", err)
		}
		if l.compareString(lName, operator, val) {
			newKeys = append(newKeys, key)
		}
	}
	l.flterKeys = newKeys
	return nil
}
func (l *Level) initFilterKeys() error {
	count, err := l.redisCli.LLen(l.lKey).Result()
	if err != nil {
		return fmt.Errorf("过滤维度层次时，调用redis命令LLen出错:%s", err)
	}
	keys, err := l.redisCli.LRange(l.lKey, 0, count).Result()
	if err != nil {
		return fmt.Errorf("过滤维度层次时，调用redis命令LRange出错:%s", err)
	}
	l.flterKeys = keys
	return nil
}
func (l *Level) compareString(s, operator, sep string) bool {
	switch operator {
	case "like":
		if strings.Index(s, sep) != -1 {
			return true
		}
	case "leftlike":
		if strings.Index(s, sep) == 0 {
			return true
		}
	case "rightlike":
		if strings.LastIndex(s, sep) == len(s)-len(sep) {
			return true
		}
	default:
		if s == sep {
			return true
		}
	}
	return false
}
func (l *Level) compareNumber(v1 float64, operator string, v2 float64) bool {
	switch operator {
	case ">":
		return v1 > v2
	case ">=":
		return v1 >= v2
	case "<":
		return v1 < v2
	case "<=":
		return v1 <= v2
	default:
		return v1 == v2
	}
}

//FilterByMeasure 通过维度层次度量值过滤
func (l *Level) filterByMeasure(indexID, operator string, val float64, context string, cacheKey string, isRow bool) error {
	newKeys := make([]string, 0, 50)
	var chKey string
	for _, key := range l.flterKeys {
		if isRow {
			chKey = cacheKey + ":h:" + key
			if context != "" {
				chKey += ":" + context
			}
		} else {
			chKey = cacheKey + ":h:" + context + ":" + key
		}
		sVal, err := cacheRedisCli.HGet(chKey, indexID).Result()
		if err != nil {
			return fmt.Errorf("过滤维度层次时，调用redis命令HGet出错:%s", err)
		}
		fVal, err := strconv.ParseFloat(sVal, 64)
		if err != nil {
			return fmt.Errorf("过滤维度层次时，在查询缓存:%s中，指标:%s，值:%s不是数字！", cacheKey, indexID, sVal)
		}
		if l.compareNumber(fVal, operator, val) {
			newKeys = append(newKeys, key)
		}
	}
	l.flterKeys = newKeys
	return nil
}

//GetKeys 获取维度层析的键值
func (l *Level) GetKeys() ([]string, error) {
	if l.flterKeys == nil {
		if err := l.initFilterKeys(); err != nil {
			return nil, err
		}
	}
	return l.flterKeys, nil
}

//SetSortByLabel 按照维度层次名称对维度进行过滤
func (l *Level) SetSortByLabel(order string) *Level {
	s := sort{
		Type:  "label",
		Order: order,
	}
	l.sorts = append(l.sorts, s)
	return l
}

//SetSortByMeasure 按照某个度量值对维度进行过滤
func (l *Level) SetSortByMeasure(name, order, context string) *Level {
	s := sort{
		Type:    "measure",
		Column:  name,
		Order:   order,
		Context: context,
	}
	l.sorts = append(l.sorts, s)
	return l
}

//SetSortByProperty 按照维度属性对维度进行过滤
func (l *Level) SetSortByProperty(name, order string) *Level {
	s := sort{
		Type:   "property",
		Column: name,
		Order:  order,
	}
	l.sorts = append(l.sorts, s)
	return l
}
func (l *Level) sortByName(name, order string, isAlpha bool, cacheKey string) error {
	store := cacheKey + ":s:" + name + ":" + order
	lock := store + ":lock"
	for {
		ex, err := l.redisCli.Exists(store).Result()
		if err != nil {
			return fmt.Errorf("排序维度层次时，调用redis命令Exists出错:%s", err)
		}
		if ex == 0 {
			ok, err := l.redisCli.SetNX(lock, "0", 10*time.Second).Result()
			if err != nil {
				return fmt.Errorf("排序维度层次时，调用redis命令SetNX出错:%s", err)
			}
			if !ok {
				time.Sleep(time.Second)
			} else {
				lk := l.lKey
				if l.flterKeys != nil {
					uuid := uuid.NewV4()
					uKey := uuid.String()
					fLen := len(l.flterKeys)
					fKeys := make([]interface{}, fLen, fLen)
					for i, key := range l.flterKeys {
						fKeys[i] = key
					}
					if err := l.redisCli.RPush(uKey, fKeys...).Err(); err != nil {
						return fmt.Errorf("排序维度层次时，调用redis命令RPush出错:%s", err)
					}
					lk = uKey
				}
				by := fmt.Sprintf("%s*->%s", l.hKey, name)
				so := redis.Sort{
					By:    by,
					Alpha: isAlpha,
					Order: order,
				}
				l.redisCli.Sort(lk, &so)
				if err := l.redisCli.Expire(store, 8*time.Hour).Err(); err != nil {
					return fmt.Errorf("排序维度层次时，调用redis命令Expire出错:%s", err)
				}
			}
		} else {
			break
		}
	}
	count, err := l.redisCli.LLen(store).Result()
	if err != nil {
		return fmt.Errorf("排序维度层次时，调用redis命令LLen出错:%s", err)
	}
	sortKeys, err := l.redisCli.LRange(store, 0, count).Result()
	if err != nil {
		return fmt.Errorf("排序维度层次时，调用redis命令LRange出错:%s", err)
	}
	if err := l.redisCli.Del(lock).Err(); err != nil {
		return fmt.Errorf("排序维度层次时，调用redis命令Del出错:%s", err)
	}
	l.flterKeys = sortKeys
	return nil
}

//SortByMeasure 按照某个度量值对维度进行过滤
func (l *Level) sortByMeasure(indexID, order string, context string, cacheKey string, isRow bool) error {
	store := cacheKey + ":z:" + indexID
	lock := store + ":lock"
	var chKey string
	for {
		ex, err := l.redisCli.Exists(store).Result()
		if err != nil {
			return fmt.Errorf("排序维度层次时，调用redis命令Exists出错:%s", err)
		}
		if ex == 0 {
			ok, err := l.redisCli.SetNX(lock, "0", 10*time.Second).Result()
			if err != nil {
				return fmt.Errorf("排序维度层次时，调用redis命令SetNX出错:%s", err)
			}
			if !ok {
				time.Sleep(time.Second)
			} else {
				for _, key := range l.flterKeys {
					if isRow {
						chKey = cacheKey + ":h:" + key
						if context != "" {
							chKey += ":" + context
						}
					} else {
						chKey = cacheKey + ":h:" + context + ":" + key
					}
					sVal := cacheRedisCli.HGet(chKey, indexID).Val()
					if sVal == "" {
						sVal = "0"
					}
					fVal, err := strconv.ParseFloat(sVal, 64)
					if err != nil {
						return fmt.Errorf("过滤维度层次时，在查询缓存:%s中，指标:%s，值:%s不是数字！", cacheKey, indexID, sVal)
					}
					member := redis.Z{
						Score:  fVal,
						Member: key,
					}
					l.redisCli.ZAdd(store, member)
				}
			}
		} else {
			break
		}
	}
	count, err := l.redisCli.ZCard(store).Result()
	if err != nil {
		return fmt.Errorf("维度层次排序时，调用redis命令ZCard出错:%s", err)
	}
	if strings.ToUpper(order) == "ASC" {
		l.flterKeys, err = l.redisCli.ZRange(store, 0, count).Result()
	} else {
		l.flterKeys, err = l.redisCli.ZRevRange(store, 0, count).Result()
	}
	if err != nil {
		return fmt.Errorf("维度层次排序时，调用redis命令ZRange或ZRevRange出错:%s", err)
	}
	if l.redisCli.Expire(store, CacheDuration).Err(); err != nil {
		return fmt.Errorf("维度层次排序时，调用redis命令Expire出错:%s", err)
	}
	return nil
}

//FilterAndSort 执行排序和过滤
func (l *Level) FilterAndSort(cacheKey string, isRow bool) (err error) {
	if l.flterKeys == nil {
		if err := l.initFilterKeys(); err != nil {
			return err
		}
	}
	for _, s := range l.sorts {
		switch s.Type {
		case "label":
			err = l.sortByName(l.setting.NameColumn, s.Order, true, cacheKey)
		case "property":
			err = l.sortByName(s.Column, s.Order, false, cacheKey)
		case "measure":
			err = l.sortByMeasure(s.Column, s.Order, s.Context, cacheKey, isRow)
		}
		if err != nil {
			return
		}
	}
	for _, f := range l.filters {
		switch f.Type {
		case "label":
			err = l.filterByName(l.setting.NameColumn, f.Operator, f.Value)
		case "property":
			err = l.filterByName(f.Name, f.Operator, f.Value)
		case "measure":
			val, err := strconv.ParseFloat(f.Value, 64)
			if err != nil {
				return fmt.Errorf("按度量值过滤时，指定的值%s不是数字！", f.Value)
			}
			err = l.filterByMeasure(f.Name, f.Operator, val, f.Context, cacheKey, isRow)
		}
		if err != nil {
			return
		}
	}
	return
}

//GetLeafKeys 根据提供的级别键值，获取层次的叶结点的键值集合
func (l *Level) GetLeafKeys(keys ...string) ([]string, error) {
	return l.hie.getLeafKeys(l.setting.Name, keys...)
}

//GetName 获取级别的名称
func (l *Level) GetName() string {
	return l.setting.Name
}

//GetHierarchyName 获取层次的名称
func (l *Level) GetHierarchyName() string {
	return l.hie.setting.Name
}

//GetDimensionName 获取维度的名称
func (l *Level) GetDimensionName() string {
	return l.hie.dim.setting.Name
}

func (l *Level) getProperty(name string) *datapackage.Property {
	for _, prop := range l.setting.Properties {
		if prop.Name == name {
			return &prop
		}
	}
	return nil
}

//KeyValue KeyValue机构体
type KeyValue struct {
	Key      string
	Value    interface{}
	Props    map[string]interface{}
	Children []KeyValue
}

//GetNamesByKeys 通过键值获取名称
func (l *Level) GetNamesByKeys(keys []string, props ...string) ([]KeyValue, error) {
	kvs := make([]KeyValue, 0)
	for _, key := range keys {
		kv, err := l.GetNameByKey(key, props...)
		if err != nil {
			return nil, err
		}
		kvs = append(kvs, *kv)
	}
	return kvs, nil
}

//GetNameByKey 通过键值获取名称
func (l *Level) GetNameByKey(key string, props ...string) (*KeyValue, error) {
	cols := make([]string, 0)
	if props != nil {
		for _, prop := range props {
			p := l.getProperty(prop)
			if p == nil {
				return nil, fmt.Errorf("为级别%s指定的属性%s没有定义", l.setting.Name, prop)
			}
			cols = append(cols, p.Column)
		}
	}
	cols = append(cols, l.setting.NameColumn)
	rVals, err := l.redisCli.HMGet(l.hKey+key, cols...).Result()
	if err != nil {
		return nil, fmt.Errorf("通过键值获取名称时，调用redis命令HMGet出错:%s", err)
	}
	cLen := len(cols)
	kv := KeyValue{
		Key:   key,
		Value: rVals[cLen-1],
	}
	propMap := make(map[string]interface{})
	for i := 0; i < cLen-1; i++ {
		propMap[props[i]] = rVals[i]
	}
	kv.Props = propMap
	return &kv, nil
}

//GetLevel 根据唯一名称获取层次对象
func GetLevel(uName string) (*Level, string, error) {
	names := strings.Split(uName, ".")
	if len(names) < 3 {
		return nil, "", fmt.Errorf("维度层次名称：%s的格式不正确！", uName)
	}
	dim := dimsMap[names[0]]
	hie, err := dim.NewHierarchy(names[1])
	if err != nil {
		return nil, "", err
	}
	lev, err := hie.NewLevel(names[2])
	if err != nil {
		return nil, "", err
	}
	return lev, names[0], nil
}
